package falcon.server;

import java.net.InetSocketAddress;
import falcon.common.Errno;
import falcon.common.Log;
import falcon.protocol.Packet;
import falcon.protocol.Protocol;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

public final class FalconByteBufHandler extends SimpleChannelInboundHandler<ByteBuf> {

	public FalconByteBufHandler(FalconProManager manager) {
		setUser(null);
		m_id = hashCode();
		m_protocol = new Protocol();
		m_manager = manager;
		setSession(null);
	}
	
	@Override
	protected void channelRead0(ChannelHandlerContext ctx, ByteBuf buf) throws Exception {
		int errno = m_protocol.decode(buf);
		if (errno != Errno.SUCCESS) {
			Log.log("decode packet error;id=%d;errno=%d;", m_id, errno);
			channelClose();
			return;
		}
		Packet packet = m_protocol.get();
		if (packet == null) {
			return;
		}
		m_manager.addReq(packet, this);
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		m_ctx = ctx;
		InetSocketAddress addr = (InetSocketAddress) m_ctx.channel().remoteAddress();
		m_clientHost = addr.getAddress().getHostAddress();
		m_clientPort = addr.getPort();
		Log.log("id=%d;clientHost=%s;clientPort=%d", m_id, getClientHost(), getClientPort());
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		Log.log("id=%d;clientHost=%s;clientPort=%d", m_id, getClientHost(), getClientPort());
		m_manager.removeSession(m_session);
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		Log.log(cause, "id=%d;clientHost=%s;clientPort=%d", m_id, getClientHost(), getClientPort());
		m_manager.removeSession(m_session);
	}
	
	public void channelWrite(Packet packet, final boolean close) {
		ByteBuf buf = m_protocol.encode(packet);
		if (buf == null) {
			Log.log("encode ResultPacket error;id=%d", m_id);
			return;
		}
		if (!m_ctx.channel().isOpen()) {
			return;
		}
		m_ctx.writeAndFlush(buf).addListener(new ChannelFutureListener() {
			@Override
			public void operationComplete(ChannelFuture arg0) throws Exception {
				if (close) {
					channelClose();
				}
			}
		});
	}
	
	public void channelClose() {
		m_ctx.close();
	}
	
	public void setUser(String user) {
		m_user = user;
	}
	
	public boolean isLogin() {
		return m_user != null;
	}
	
	public String getClientHost() {
		return m_clientHost;
	}
	
	public int getClientPort() {
		return m_clientPort;
	}
	
	public String getUser() {
		return m_user;
	}
	
	public void setSession(FalconSession session) {
		m_session = session;
	}

	private int m_id;
	private String m_clientHost;
	private int m_clientPort;
	private String m_user;
	private Protocol m_protocol;
	private ChannelHandlerContext m_ctx;
	private FalconProManager m_manager;
	private FalconSession m_session;
}
